#include "vxzoomcontroller.h"
#include "vxcommandscontroller.h"
#include "vxmousetransmitter.h"

#include "vx.h"



VxZoomController::VxZoomController(QGraphicsView * view) :
	_view(view), _animationScale(NULL)

{
	qApp->installEventFilter(this);
	VxCommandsController * commands = VxCommandsController::instance(view);

	connect(commands, SIGNAL(zoomFitToAll()), this, SLOT(zoomFitToAll()));
	connect(commands, SIGNAL(zoomToBack()), this, SLOT(zoomToBack()));
	connect(commands, SIGNAL(zoomByWheel(int)), this, SLOT(zoomByWheel(int)));
	connect(commands, SIGNAL(cancelAnimation()), this, SLOT(cancelAnimation()));

	_animationScale = new QPropertyAnimation(this, "scale");
	_animationScale->setDuration(Vx::ZoomDelay);
	_animationScale->setEasingCurve(QEasingCurve::OutQuart);

}

VxZoomController::~VxZoomController()
{
	delete _animationScale;
}


qreal VxZoomController::getScale()
{
	return _view->matrix().m11();
}


void VxZoomController::_setScale(qreal s)
{
	QMatrix vm = _view->matrix();
	QMatrix m;
	
	m.scale(s, s);
	m.translate(vm.dx(), vm.dy());
	_view->setMatrix(m);
	
	QPointF p = _view->mapToScene(_viewPoint);
	qreal dx = _scenePoint.x() - p.x();
	qreal dy = _scenePoint.y() - p.y();

	QPoint cp = _view->viewport()->contentsRect().center();
	QPointF center = _view->mapToScene(cp);

	_view->centerOn(center.x() + dx, center.y() + dy);

}




void VxZoomController::zoomByWheel(int delta)
{
	qreal scale = getScale();
	if (_animationScale->state() != QAbstractAnimation::Stopped){
		scale = _animationScale->endValue().toInt();
	}
	if (scale < 1){
		scale = 1;
	}

	qreal endscale = -1;

	if (delta > 0)
	{
		endscale = scale*2;
	} else
	if (scale > 1){
		endscale = scale/2;
		if (endscale < 1){
			endscale = 1;
		}
	};

	_viewPoint = _view->mapFromGlobal(VxMouseTransmitter::instance()->movedPos());

	scaleToView(endscale, &_viewPoint, true);

}




VxViewPoint * VxZoomController::getViewPoint()
{
	VxViewPoint * vpoint = new VxViewPoint();
	vpoint->scale = getScale();
	vpoint->viewPoint = _view->viewport()->contentsRect().center();
	vpoint->scenePoint = _view->mapToScene(vpoint->viewPoint);
	return vpoint;
}



void VxZoomController::scaleToView(qreal scale, QPoint * viewPoint, bool animated)
{

	if (viewPoint == NULL){
		_viewPoint = _view->viewport()->contentsRect().center();
	} else {
		_viewPoint.setX(viewPoint->x());
		_viewPoint.setY(viewPoint->y());
	}

	QPointF sp = _view->mapToScene(_viewPoint);

	scaleToScene(scale, &sp, animated);

}


void VxZoomController::scaleToScene(qreal scale, QPointF * scenePoint, bool animated)
{
	qreal currentsc = getScale();

	if (currentsc == scale){
		return;
	}

	_scenePoint.setX(scenePoint->x());
	_scenePoint.setY(scenePoint->y());

	if (scale > 0){

		if (!animated){
			_setScale(scale);
			emit scaleShanged(scale);
			return;
		}

		if (_animationScale->state() == QAbstractAnimation::Running){
			_animationScale->stop();
			_setScale(_animationScale->endValue().toReal());
		}

		_animationScale->setStartValue(currentsc);
		_animationScale->setEndValue(scale);
		_animationScale->start();

		emit scaleShanged(scale);
	}
}


void VxZoomController::setViewPoint(VxViewPoint * vpoint, bool animated)
{
	_viewPoint = _view->viewport()->contentsRect().center();
	scaleToScene(vpoint->scale, &vpoint->scenePoint, animated);
}


void VxZoomController::zoomFitToAll(bool animated)
{

	_backScale = getViewPoint();

	QRectF scner = _view->contentsRect();
	QRectF itmsr = _view->scene()->itemsBoundingRect();

	_viewPoint = _view->viewport()->contentsRect().center();

	qreal vs = scner.height()/itmsr.height();
	qreal hs = scner.width()/itmsr.width();
	qreal s = (vs > hs) ? hs : vs;

	QPointF cp = itmsr.center();
	s -= s/10;
	if (s > 1){
		s = 1;
	}
	scaleToScene(s, &cp, animated);
}


void VxZoomController::zoomToBack(bool animated)
{
	_viewPoint = _backScale->viewPoint;
	scaleToScene(_backScale->scale, &_backScale->scenePoint, animated);
}


void VxZoomController::cancelAnimation()
{
	if (_animationScale){
		_animationScale->stop();
	}
}


void VxZoomController::scaleTo(qreal scale)
{
	cancelAnimation();
	_view->resetMatrix();
	_view->scale(scale, scale);
	qApp->processEvents();
	emit scaleShanged(getScale());
}


void VxZoomController::_animationScaleFinished()
{
	emit scaleShanged(getScale());
}


void VxZoomController::centerOn(QPointF vp)
{
	_view->centerOn(vp);
	emit scaleShanged(getScale());
}

